package main.model.parser;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;


/**
 * Parent Parsing class for delimited data files (csv, tabular, etc.).
 *
 * @author Michele Reshef
 *
 */
public abstract class DelimitedParseStrategy extends ParseStrategy {
    private static final String FLOAT_PATTERN = "^\\s*[-+]?[0-9]*\\.?[0-9]*\\s*$";
    private static final String POS_INT_PATTERN = "^\\s*[+]?[0-9]+\\s*$";
    private static final String ENG_DATE_PATTERN = "^\\s*\\d{1,2}/\\d{1,2}/\\d{1,2}\\s*$";
    private final String myDelimiter;

    /**
     * constructor
     *
     * @param d delimiter
     */
    public DelimitedParseStrategy (String d) {
        myDelimiter = d;
    }

    @Override
    public Map<String, Object> parseLineToRow (String line) throws ParseException {

        Map<String, Object> data = new HashMap<String, Object>();
        Scanner s = getScanner(line);

        for (int i = 0; i < getNumHeaders() && s.hasNext(); i++) {
            String field = s.next();
            Object convertedObj;

            // Do some pattern matching to pick appropriate data type
            // match positive integer
            if (field.matches(POS_INT_PATTERN)) {
                convertedObj = Integer.parseInt(field);
            }
            // match floating point
            else if (field.matches(FLOAT_PATTERN)) {
                convertedObj = Float.parseFloat(field);
            }
            // match date pattern
            else if (field.matches(ENG_DATE_PATTERN)) {
                SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
                // may throw parse exception here
                convertedObj = formatter.parse(field);
            }
            // Default case is to leave it as a string
            else {
                convertedObj = field;
            }

            // put it into the data row
            data.put(getHeaderAt(i).toLowerCase(), convertedObj);
        }
        return data;
    }

    /**
     * gets Scanner to use as delimiter when parsing
     *
     * @param line line input
     * @return
     */
    protected Scanner getScanner (String line) {
        Scanner s = new Scanner(line);
        s.useDelimiter(myDelimiter);
        return s;
    }

    @Override
    public void setHeaders (String line) {
        Scanner s = getScanner(line);
        while (s.hasNext()) {
            addHeader(s.next());
        }
    }

}
